﻿using Castle.DynamicProxy;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Dotnet.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Dotnet.Utils.Utility.Dependency.Castle
{
    [Obsolete("使用IocHelper")]
    public class IocManager : IIocManager, IIocRegistrar, IIocResolver
    {
        public IocManager()
        {
            IocContainer = new WindsorContainer();
            WindsorContainer iocContainer = IocContainer;
            IRegistration[] array = new IRegistration[1];
            array[0] = Component.For<IocManager, IIocManager, IIocRegistrar, IIocResolver>().UsingFactoryMethod(() => this, false);
            iocContainer.Register(array);
        }

        public static IocManager Instance { get; set; } = new IocManager();

        public void RegisterSingleton(Type type, object impl)
        {
            if (IocContainer.Kernel.HasComponent(type) || IocContainer.Kernel.HasComponent(impl.GetType()))
            {
                IocContainer.Register(new IRegistration[]
                {
                    Component.For(type).Named(Guid.NewGuid().ToString("n")).Instance(impl).IsDefault()
                });
            }
            else
            {
                IocContainer.Register(new IRegistration[]
                {
                    Component.For(type).Instance(impl).IsFallback()
                });
            }
        }

        public T Resolve<T>()
        {
            return IocContainer.Resolve<T>();
        }

        public object Resolve(Type type)
        {
            return IocContainer.Resolve(type);
        }

        public void RegisterAssembly(Assembly assembly)
        {
            IocContainer.Register(new IRegistration[]
            {
                Classes.FromAssembly(assembly).IncludeNonPublicTypes().BasedOn<ITransientDependency>().WithServiceSelect(new ServiceDescriptor.ServiceSelector(ServiceInterfacesSelector)).LifestyleTransient()
            });
            IocContainer.Register(new IRegistration[]
            {
                Classes.FromAssembly(assembly).IncludeNonPublicTypes().BasedOn<ISingletonDependency>().WithServiceSelect(new ServiceDescriptor.ServiceSelector(ServiceInterfacesSelector)).LifestyleSingleton()
            });
            IocContainer.Register(new IRegistration[]
            {
                Classes.FromAssembly(assembly).IncludeNonPublicTypes().BasedOn<IInterceptor>().WithService.Self().LifestyleTransient()
            });
        }

        private IEnumerable<Type> ServiceInterfacesSelector(Type type, Type[] baseTypes)
        {
            IList<Type> list;
            if (type.BaseType == null)
            {
                list = type.GetInterfaces();
            }
            else
            {
                list = type.GetInterfaces().Except(type.BaseType.GetInterfaces()).ToList();
            }
            IEnumerable<Type> result;
            if (!list.Any((p) => p == typeof(ITransientDependency) || p == typeof(ISingletonDependency) || p == typeof(IInterceptor)))
            {
                result = new Type[0];
            }
            else
            {
                list = (from p in list
                        where p != typeof(ITransientDependency) && p != typeof(ISingletonDependency) && p != typeof(IInterceptor)
                        select p).ToList();
                if (list.Any())
                {
                    list.Add(type);
                }
                result = list;
            }
            return result;
        }

        public WindsorContainer IocContainer { get; set; }

        public void Register(Type type, Type impl)
        {
            Register(type, impl, DependencyLifeStyle.Singleton);
        }

        public void Register(Type type, Type impl, DependencyLifeStyle lifeStyle)
        {
            if (IocContainer.Kernel.HasComponent(type) || IocContainer.Kernel.HasComponent(impl))
            {
                IocContainer.Register(new IRegistration[]
                {
                    ApplyLifestyle<object>(Component.For(new Type[]
                    {
                        type,
                        impl
                    }).Named(Guid.NewGuid().ToString("n")).ImplementedBy(impl).IsDefault(), lifeStyle)
                });
            }
            else
            {
                IocContainer.Register(new IRegistration[]
                {
                    ApplyLifestyle<object>(Component.For(new Type[]
                    {
                        type,
                        impl
                    }).ImplementedBy(impl).IsFallback(), lifeStyle)
                });
            }
        }

        public void Register<TType, TImpl>() where TType : class where TImpl : class, TType
        {
            Register<TType, TImpl>(DependencyLifeStyle.Singleton);
        }

        public void Register<TType, TImpl>(DependencyLifeStyle lifeStyle) where TType : class where TImpl : class, TType
        {
            if (IocContainer.Kernel.HasComponent(typeof(TType)) || IocContainer.Kernel.HasComponent(typeof(TImpl)))
            {
                IocContainer.Register(new IRegistration[]
                {
                    ApplyLifestyle(Component.For<TType, TImpl>().Named(Guid.NewGuid().ToString("n")).ImplementedBy<TImpl>().IsDefault(), lifeStyle)
                });
            }
            else
            {
                IocContainer.Register(new IRegistration[]
                {
                    ApplyLifestyle(Component.For<TType, TImpl>().ImplementedBy<TImpl>().IsFallback(), lifeStyle)
                });
            }
        }

        private static ComponentRegistration<T> ApplyLifestyle<T>(ComponentRegistration<T> registration, DependencyLifeStyle lifeStyle) where T : class
        {
            ComponentRegistration<T> result;
            switch (lifeStyle)
            {
                case DependencyLifeStyle.Singleton:
                    result = registration.LifestyleSingleton();
                    break;

                case DependencyLifeStyle.Transient:
                    result = registration.LifestyleTransient();
                    break;

                default:
                    result = registration;
                    break;
            }
            return result;
        }
    }
}